import 'package:family_expense/features/income_expense/constants/income_expense_type.dart';
import 'package:family_expense/features/income_expense_detail_type/models/income_expense_detail_type.dart';
import 'package:family_expense/features/income_expense_detail_type/services/income_expense_detail_type_service.dart';
import 'package:flutter/material.dart';
import 'package:my_flutter_core/my_flutter_core.dart';

class EditIncomeExpenseDetailType extends StatefulWidget {
  const EditIncomeExpenseDetailType(this.detailType, {super.key});

  // final String incomeExpenseType;
  final IncomeExpenseDetailType detailType;

  @override
  State<EditIncomeExpenseDetailType> createState() =>
      _EditIncomeExpenseDetailTypeState();
}

class _EditIncomeExpenseDetailTypeState
    extends State<EditIncomeExpenseDetailType> {
  // For form validation.
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();

  // For any income/expense detail type interaction with back end service.
  final IncomeExpenseDetailTypeService _detailTypeService =
      IncomeExpenseDetailTypeService();

  // Indicates current action is adding new data or updating data.
  // If [id] does not exist that means is adding new data.
  late final bool _addNew = widget.detailType.id == null;

  // Current income/expense detail type data.
  late IncomeExpenseDetailType _detailType;

  @override
  void initState() {
    super.initState();

    _createIncomeExpenseDetailType();
  }

  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: false,
      onPopInvokedWithResult: _onPopInvokedWithResult,
      child: Scaffold(
        appBar: AppBar(
          title: Text(
            '${_addNew ? '添加' : '修改'}${IncomeExpenseType.getCategories()[_detailType.incomeExpenseType!]}类别',
          ),
        ),
        body: _buildForm(),
      ),
    );
  }

  /// Builds the input form.
  Widget _buildForm() {
    // DO NOT PUT [Form] in [ListView]. Uses [SingleChildScrollView] instead.
    // Textfield in gallery gets reset if scrolled out of view.
    // https://github.com/flutter/flutter/issues/11500
    return Form(
      key: _formKey,
      child: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16.0),
              child: TextFormField(
                keyboardType: TextInputType.text,
                textCapitalization: TextCapitalization.characters,
                initialValue: _detailType.name ?? '',
                decoration: const InputDecoration(
                  labelText: '名称',
                  hintText: '下划线间隔大写英文单词，不可与其它名称重名。',
                ),
                validator: (value) => FormTextFieldValidator(
                  '名称',
                  value,
                  maxLength: IncomeExpenseDetailType.nameMaxLength,
                  patterns: [
                    ValidatorPattern(r'[^a-zA-Z0-9_]+', '只接受英文单词、数字和下划线'),
                  ],
                ).validate(),
                onSaved: (value) {
                  _detailType.name = value;
                },
              ),
            ),
            _buildDivider(),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16.0),
              child: TextFormField(
                keyboardType: TextInputType.text,
                initialValue: _detailType.title ?? '',
                decoration: const InputDecoration(
                  labelText: '标题',
                  hintText: '中文标题',
                ),
                validator: (value) => FormTextFieldValidator(
                  '标题',
                  value,
                  maxLength: IncomeExpenseDetailType.titleMaxLength,
                ).validate(),
                onSaved: (value) {
                  _detailType.title = value;
                },
              ),
            ),
            _buildDivider(),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16.0),
              child: TextFormField(
                keyboardType: TextInputType.text,
                initialValue: _detailType.subtitle ?? '',
                decoration: const InputDecoration(
                  labelText: '子标题',
                  hintText: '中文子标题，用于额外说明。',
                ),
                validator: (value) => FormTextFieldValidator(
                  '子标题',
                  value,
                  isRequired: false,
                  maxLength: IncomeExpenseDetailType.subtitleMaxLength,
                ).validate(),
                onSaved: (value) {
                  _detailType.subtitle = value;
                },
              ),
            ),
            _buildDivider(),
            SwitchListTile(
              title: const Text('分析包含'),
              subtitle: const Text('收支分析时是否包含该项数据'),
              value: _detailType.analysisIncluded!,
              onChanged: (value) {
                if (mounted) {
                  // Triggers build.
                  setState(
                    () => _detailType.analysisIncluded =
                        !_detailType.analysisIncluded!,
                  );
                }
              },
            ),
            _buildDivider(),
            Container(
              margin: const EdgeInsets.only(top: 60.0),
              height: 44.0,
              child: PressStatusButton(
                onPressed: _save,
                disabledChild: const Text(
                  '正在保存',
                  style: TextStyle(fontSize: 20.0),
                ),
                child: const Text('保 存', style: TextStyle(fontSize: 20.0)),
              ),
            ),
          ],
        ),
      ),
    );
  }

  /// Builds divider between list tile.
  Widget _buildDivider() {
    return const SizedBox(height: 20.0);
  }

  /// Creates new instance of [IncomeExpenseDetail] based on current widget argument.
  void _createIncomeExpenseDetailType() {
    // If user comes from [IncomeExpenseDetailTypeInfo] the provided argument already contains all necessary data.
    // In order to void updating original data we need to clone it.
    _detailType = widget.detailType.clone();

    // Sets the recommended prefix for new detail type.
    if (_addNew) {
      _detailType.name = '${_detailType.incomeExpenseType}_';
    }
  }

  /// Saves the new [IncomeExpenseDetailType] to server and pops.
  /// When pops notify previous page to reload.
  Future<void> _save() async {
    // Validate returns true if the form is valid, or false otherwise.
    if (!_formKey.currentState!.validate()) {
      showToast('请正确填写各项信息');
      return;
    }

    // Saves current form.
    _formKey.currentState!.save();

    // Checks if the name already exists.
    final checkExisting = await _detailTypeService.checkExisting(
      _detailType.incomeExpenseType!,
      _detailType.id,
      _detailType.name!,
    );

    if (!checkExisting) {
      IncomeExpenseDetailType updatedData;

      if (_addNew) {
        // Saves the new bank card and pops if successful.
        updatedData = await _detailTypeService.add(_detailType);
      } else {
        // Saves the updated bank card and pops if successful.
        updatedData = await _detailTypeService.update(_detailType);
      }

      // DO NOT use BuildContext across asynchronous gaps.
      // https://dart-lang.github.io/linter/lints/use_build_context_synchronously.html
      if (mounted) {
        // Pops current page and returns to the detail view.
        // Pop method will not trigger WillPopScope.
        NavigatorHelper.pop(context, updatedData);
      }
    } else {
      showToast('${_detailType.name} 已存在，请更换其它名称后重试。');
    }
  }

  /// Checks the data before popping.
  void _onPopInvokedWithResult(bool didPop, dynamic result) {
    if (didPop) {
      return;
    }

    // If we check the if the data identical that means we have to call [_formKey.currentState.save()] first.
    // Then it would call validation and might failed. That's why we show the confirm directly.
    showConfirmDialog(
      context,
      '放弃保存？',
      onConfirm: () {
        // If user pops current view directly, that means nothing updated.
        NavigatorHelper.pop(context);
      },
    );
  }
}
